Did you know ... Search Documentation:
Pack lps_corner -- wiki.git/Syntax of lps.swi.md

Syntax of LPS

[TOC]

lps.swi is the LPS implementation based on SWI-Prolog. The surface syntax used in lps.js is slightly different.

The current syntax of LPS is essentially a superset of @SWI-Prolog](http://www.swi-prolog.org), adding a flexible mixture of explicit and implicit time and some additional rules and declarations.

Comments

% 	written either in this form
/* or in this form, which is convenient if they occupy several lines.
*/

Declarations:


maxTime(_).
fluents 		…  .
events   	…  .
actions 	…  .

Inputs


initially 	…  .
observe  	…   .

Reactive rules


if …  then …  .

Clauses for time-dependent predicates

… if …  .

Clauses for timeless predicates (e.g. Prolog)

… :- …  .

Causal laws


… initiates … if …  .
… terminates … if …  .

Constraints

false …  .

In more detail:

Declarations.

#!

maxTime(_).

This is an optional declaration of the maximum number of states. If the declaration is not present, the maximum is currently set at 20 by default.

#!

fluents    fluent1, fluent2, …, fluentn.	% n >= 1

Fluents are time-dependent atomic sentences. Here they are specified by giving the name of the fluent followed by its arguments. For example, a two-argument fluent named location could be specified by any one of location/2, location(_,_), or location(_object, _place), where _, _object, and _place are “anonymous variables”.

Fluents can be “extensional” if they are represented by “facts” and updated by events or “intensional” if they are represented by clauses that mirror changes of the extensional fluents.

#!

events    event1, event2, … , eventn.	% n >= 1.

Events can be external, given by observations, or generated by the system. They can be “atomic”, taking place instantaneously from one state to the next, or “composite”, taking place over a series of zero or more states. For example, say/2, say(_,_) or say(_agent, _expression).

#!

actions    action1, action2, …, actionn.	% n >= 1.

Actions are “atomic”, taking place instantaneously, and are generated by the system. They have the same syntax as events, and can also be declared as events, which may be external.

Inputs.

#!

initially   fluent1, fluent2, … , fluentn.	% n >= 1.

This specifies the extensional fluents that are true in the initial state at time 0.

#!

observe  event1, event2, … , eventn from time1 to time2.	% n >= 1.

time1 and time2 should be successive positive integers, e.g. from 2 to 3. The program can have multiple observe statements with different times.

Reactive rules.

#!

if literal1, … , literaln then literaln+1, … , literaln+m.	% n >= 1 and m >= 1.

Each literal is a timed or untimed atomic formula or the negation of an atomic formula. (See below.) Implicitly all times after "then" are later than or equal to the latest time before "then". Also, no time after a comma is earlier than any time before the same comma.

Clauses for time-dependent predicates.

#!

atomic formula if literal1, … , literaln.  	% n > 1.
#!

atomic formula.  				% n = 0.

These clauses are used to define:

  • 1) intensional predicates, which change as a consequence of changes to extensional predicates. For example (with explicit time)
    #!
    
    location(Object, Place) at T if holding(Agent, Object) at T,  location(Agent, Place) at T.

    These can also be written without explicit time:

    #!
    
    location(Object, Place) if holding(Agent, Object), location(Agent, Place).
  • 2) composite actions and events, which can take place over zero or more state transitions. For example (with explicit time):
    #!
    
    makeAt(Agent, Place) from T to T if location(Agent, Place) at T.
    makeAt(Agent, Place) from T1 to T2 if not location(Agent, Place) at T1,move(Agent, Place) from T1 to T2.

    Traditional clauses in Prolog are also allowed:

    #!prolog
    
    atomic formula :- literal1, … , literaln.     	% n > 0.

    These clauses can be used to define time-independent predicates directly in Prolog. For example,

    #!prolog
    
    parent(X,Y) :- mother(X,Y).
    parent(X,Y) :- father(X,Y).

    The implementation does not support the logical connective for disjunction. So the following definition of parent does not work.

    #!prolog
    
    
    parent(X,Y) :- mother(X,Y);father(X,Y).
    

    Prolog predicates includes all time-independent predicates, including temporal inequalities, e.g. philosopher(hume) and T1 < T2.

Causal laws

#!

event initiates fluent if literal1, … , literaln.	% n > 0.

Here event is an external event or an atomic (non-composite) action. event, fluent and literals can all be written without explicit time. Implicitly, if the event takes place from T to T+1 then fluent is true at time T+1 if all the literals are true at time T.

Do we allow the literals be events? (to be answered).

#!

event terminates fluent if literal1, … , literal. 	% n > 0.

Like initiates, implicitly, if the event takes place from T to T+1 then the fluent at time T is terminated. It is possible for a fluent to be initiated and terminated at the same time, but by different events, as for example, when a subscription runs out, but is renewed at the same time.

Constraints.

#!

false   literal1, literal2, … , literaln.   % n > 1

These are used to constrain candidate actions, say from T to T+1. So one of the literals must be an action. Other literals can be actions or external events that also occur from T to T+1. They can also be fluents that are true at time T. Because of these restrictions on time, these constraints can be written without explicit time.

Fluent literals in constraints can be negative literals, but action and other event literals can not be negated.

Literals

#!prolog

predicate(term1, term2, … , termn)   % n > 0

Such literals are also called (untimed) atomic formulas, or simply atoms, and can be fluents, events, or time-independent. The predicate must start with a lower case letter. The terms can be variables, constants (numbers or strings starting with a lower case letter), numbers, or any expression allowed by Prolog.

Variables follow the Prolog convention of starting with an upper case letter, or with _ if their name does not matter because it does not occur elsewhere in the same sentence.

#!prolog

not atom

atom can be an atomic fluent. Other uses of negation are under investigation.

#!prolog

fluent at T

Here T is a time variable. However, the possibility that T may be a constant time has not been excluded.

#!prolog

event from T1 to T2
event from T1
event to T2

These all have their obvious intended meanings.

Notes

  • 1) Most of the components listed above are optional. To be meaningful an LPS program needs only reactive rules and actions, for example, the program:
    #!
    
    actions rain.
    if true then rain.
    if rain then rain.

    generates a sequence of 19 actions:

    #!
    
    rain, rain, …, rain.
  • 2) Literals in reactive rules and clauses are processed Prolog-like, in the order in which they are written. Processing is suspended if the time of a fluent or the start time of an event is later than the current time, or if the time is a variable and the literal cannot be made true at the current time, but might become true later.
  • 3) Times can be omitted from fluents and events. However, for this to work, composite events and actions need to be declared as events, and intensional fluents need to be declared as fluents. This feature is currently under development, and is subject to change. Implicit and explicit times can be mixed in the same sentence. Currently, the interpreter interprets implicit times according to the following rules: The expression:
    #!
    
    fluent1, fluent2

    means

    #!prolog
    
    fluent1 at T1, fluent2 at T2, T1 =< T2.

    The expression:

    #!
    
    fluent, event

    means

    #!prolog
    
    fluent at T1, event from T2 to T3, T1 =< T2.

    The expression:

    #!
    
    event1, event2

    means

    #!prolog
    
    event1 from T1 to T2, event2 from T3 to T4, T2 =< T3.

    The expression:

    #!
    
    event, fluent

    means

    #!prolog
    
    event from T1 to T2, fluent at T3, T2 =< T3.

    The expression:

    #!
    
    event if conditions

    means

    #!prolog
    
    event from T1 to Tn if conditions

    where T1 is the earliest time in conditions and Tn is the latest time in conditions.

    The expression:

    #!
    
    fluent if conditions

    means

    #!prolog
    
    fluent at T if conditions
    

    where all the time variables in conditions are identical to T.

  • * *

LPS syntax (tentative) summary ##

Files have the .lps extension and (more or less) the following structure. Please, beware, this is just a rough approximation:

#!

  spec ::= statement
  statement ::= settings rules
  settings ::= max_time actions fluents initial_state observations
  rules ::= if_then_rules if_rules  initiate_rules terminate_rules constraints
  if_rules ::= if_rule | if_rule if_rules
  if_rule ::= literal "." | literal "if" conjunction "." | literal ":-" conjunction  "."
  if_then_rules ::= if_then_rule | if_then_rule if_then_rules
  if_then_rule ::= "if" conjunction "then" conjunction "."
  constraints ::= constraint | constraint constraints
  constraint ::= "false" conjunction "."
  conjunction ::= "true" | literal | literal "," conjunction
  • * *

Internal syntax ##

NOTE: to see your program in this syntax, use `dump.`in the SWISH query panel.

Files have the .lpsw extension and (more or less) the following structure:

#!

  spec ::= statement
  statement ::= settings rules
  settings ::= max_time  actions  fluents  initial_state  observations  events
  rules ::= if_rules reactive_rules initiate_rules terminate_rules constraints
  if_rules ::= if_rule | if_rule if_rules
  if_rule ::= timeless_rule | event_rule | prolog_clause
  timeless_rule ::= "l_timeless(" literal "," conjunction ")."
  event_rule ::= "l_events(" happens_literal "," hold_conjunction_list ")."
  reactive_rules ::= if_then_rule | if_then_rule if_then_rules
  if_then_rule ::=  "reactive_rule(" conjunction "," conjunction ")."
  constraints ::= constraint | constraint constraints
  constraint ::= "d_pre(" conjunction ")."
  conjunction ::= "true" | literal | literal "," conjunction